import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';

export interface ISpinBoxProps {
  onChange?: (value: number) => void;
  minValue?: number;
  maxValue?: number;
  step?: number;
  editable: boolean;
  disabled?: boolean;
  defaultValue?: number;
  small?: boolean;
  className?: string;
  style?: React.CSSProperties;
}

export interface ISpinBoxStates {
  value: number;
  step: number;
}

export class SpinBox extends React.Component<ISpinBoxProps, ISpinBoxStates> {
  public static defaultProps = {
    editable: true,
  };
  public static propTypes = {
    onChange: PropTypes.func,
    minValue: PropTypes.number,
    maxValue: PropTypes.number,
    step: PropTypes.number,
    editable: PropTypes.bool.isRequired,
    disabled: PropTypes.bool,
    defaultValue: PropTypes.number,
    small: PropTypes.bool,
    className: PropTypes.string,
    style: PropTypes.object,
  };
  constructor(props: ISpinBoxProps) {
    super(props);
    this.state = {
      value: this.props.defaultValue ? this.props.defaultValue : 1,
      step: this.props.step ? this.props.step : 1,
    };
    this.handleOnChange = this.handleOnChange.bind(this);
    this.handleAddClick = this.handleAddClick.bind(this);
    this.handleSubClick = this.handleSubClick.bind(this);
  }

  public handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {
    let result;
    let maxValue = this.props.maxValue;
    if (maxValue) {
      if (maxValue >= 999999) {
        maxValue = 999999;
      }
    }
    let minValue = this.props.minValue;
    let value: string = event.target.value.replace(/[^\d]/g, '');
    if (!value) {
      value = '0';
    }
    if (!minValue && !maxValue) {
      if (parseInt(value, 10) >= 999999) {
        result = 999999;
      } else {
        result = parseInt(value, 10);
      }
    } else if (minValue && !maxValue) {
      if (parseInt(value, 10) <= minValue) {
        result = minValue;
      } else {
        result = parseInt(value, 10);
      }
    } else if (!minValue && maxValue) {
      if (parseInt(value, 10) >= maxValue) {
        result = maxValue;
      } else {
        result = parseInt(value, 10);
      }
    } else if (minValue && maxValue) {
      if (parseInt(value, 10) >= maxValue) {
        result = maxValue;
      } else if (parseInt(value, 10) <= minValue) {
        result = minValue;
      } else {
        result = parseInt(value, 10);
      }
    } else {
      result = parseInt(value, 10);
    }
    if (this.props.onChange) {
      this.props.onChange(result);
    }
    this.setState({
      value: result,
    });
  }

  public handleAddClick() {
    if (this.props.disabled) {
      return;
    }
    let result;
    let maxValue = this.props.maxValue;
    let addResult = this.state.value + this.state.step;
    if (!maxValue) {
      if (addResult >= 999999) {
        result = 999999;
      } else {
        result = addResult;
      }
    } else if (addResult > maxValue) {
      result = maxValue;
    } else {
      if (addResult >= 999999) {
        result = 999999;
      } else {
        result = addResult;
      }
    }
    if (this.props.onChange) {
      this.props.onChange(result);
    }
    this.setState({
      value: result,
    });
  }

  public handleSubClick() {
    if (this.props.disabled) {
      return;
    }
    let result;
    let minValue = this.props.minValue;
    let subResult = this.state.value - this.state.step;
    if (minValue === undefined) {
      if (subResult <= -99999) {
        result = -99999;
      } else {
        result = subResult;
      }
    } else if (subResult < minValue) {
      result = minValue;
    } else {
      if (subResult <= -99999) {
        result = -99999;
      } else {
        result = subResult;
      }
    }
    if (this.props.onChange) {
      this.props.onChange(result);
    }
    this.setState({
      value: result,
    });
  }

  public render() {
    let editable = this.props.editable;
    if (editable === undefined) {
      editable = false;
    } else {
      editable = !this.props.editable;
    }
    const boxSize = this.props.small ? 'br-spin-box--small' : 'br-spin-box--large';
    const classString = classNames('br-spin-box', 'no-user-select', boxSize, this.props.className);
    return (
      <div className={classString} style={this.props.style}>
          <span className="br-spin-box__sub" onClick={this.handleSubClick}>
            <i className="icon icon-subtract br-spin-box__sub-icon"></i>
          </span>
          <input
            readOnly={editable}
            disabled={this.props.disabled}
            className="br-spin-box__input"
            onChange={(e) => this.handleOnChange(e)}
            value={this.state.value}
            type="text"
          />
          <span className="br-spin-box__add" onClick={this.handleAddClick}>
            <i className="icon icon-add br-spin-box__add-icon"></i>
          </span>
        </div>
    );
  }
}
